package com.cxhd.pacs;

/*
  COPYRIGHT NOTICE
  Copyright (c) 2012  Scott C. Neu and Arthur W. Toga

  This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.FileImageInputStream;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;

/**
 * Example that illustrates how to use the LONI Image I/O plugins to display
 * the first image from a file.
 * <p>
 * NOTE:  Running requires the plugin corresponding to the format of the
 *        file whose image is being displayed.
 *
 * @version 23 July 2012
 */
public class ImageViewer
{
    /**
     * Constructs an Image Viewer.
     *
     * @param fileName Name of the file to read an image from.
     */
    public ImageViewer(String fileName)
    {
	try {

	    // Reorder the registered Image Reader SPI's
	    _reorderImageReaderSpis();

	    // Test the file existence
	    File file = new File(fileName);
	    if ( !file.exists() || !file.isFile() || !file.canRead() ) {
		System.out.println("Cannot read \"" + fileName + "\"");
		System.exit(1);
	    }

	    // Find an Image Reader for the file
	    ImageReader imageReader = _getImageReader(file);
	    if (imageReader == null) {
		System.out.println("Cannot decode \"" + fileName + "\"");
		System.exit(1);
	    }

	    // Read the first image
	    BufferedImage bufferedImage = imageReader.read(0);

	    // Create a JFrame for the image
	    JFrame frame = new JFrame(fileName);
	    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	    // Place the components in a Box Layout
	    Box box = new Box(BoxLayout.Y_AXIS);
	    frame.getContentPane().add(box);

	    // Add the image
	    box.add( new ImageComponent(bufferedImage) );

	    // Display the JFrame
	    frame.pack();
	    frame.setSize(bufferedImage.getWidth(), bufferedImage.getHeight());
	    frame.setVisible(true);
	}

	catch (Exception e) {
	    e.printStackTrace();
	    System.exit(1);
	}
    }

    /**
     * Main method.
     *
     * @param args Command line parameters.
     */
    public static void main(String[] args) 
    {
//	if (args.length < 1) {
//	    System.out.println("ARGS:  <file>");
//	    System.exit(1);
//	}

	// Read and display the first image from the file
	new ImageViewer("C:\\data\\1.3.6.1.4.1.36280.1.0.1.1.2016102794917.88610.14.dcm");
    }

    /**
     * Gets an Image Reader that can decode the specified file.
     *
     * @param file File to find an Image Reader for.
     *
     * @return Image Reader that can decode the specified file, or null if none
     *         was found.
     *
     * @throws IOException If an I/O error occurs.
     */
    private ImageReader _getImageReader(File file) throws IOException
    {
	Object input = new FileImageInputStream(file);
	Object origInput = input;

	// First look for a magic number in the header
	Iterator iter = ImageIO.getImageReaders(input);

	// No Image Reader is found
	if ( !iter.hasNext() ) {

	    // Then look in the directory of the file (e.g., ANALYZE, AFNI)
	    input = file;
	    iter = ImageIO.getImageReaders(input);

	    // No Image Reader is found
	    if( !iter.hasNext() ) {
		input = origInput;

		// Then look at the file name suffix
		String temp = file.getName();
		String[] strings = temp.split("\\.");

		if (strings.length > 1) {
		    int l = strings.length;
		    String suffix = strings[l-1];
		    iter = ImageIO.getImageReadersBySuffix(suffix);
		}
		if ( !iter.hasNext() ) {
		    if (strings.length > 2) {
			int l = strings.length;
			String suffix = strings[l-2] + "." + strings[l-1];
			iter = ImageIO.getImageReadersBySuffix(suffix);
		    }
		}

		// No Image Reader found
		if ( !iter.hasNext() ) { return null; }
	    }
	}

	// Set the Input Stream of the first Image Reader returned
	ImageReader imageReader = (ImageReader)iter.next();
	imageReader.setInput(input);

	// Return the Image Reader
	return imageReader;
    }

    /** JComponent used to display a Buffered Image. */
    private class ImageComponent extends JComponent
    {
	/** Buffered Image displayed in the JComponent. */
	private BufferedImage _bufferedImage;

	/**
	 * Constructs an Image Component.
	 *
	 * @param bufferedImage Buffered Image displayed in the JComponent.
	 */
	public ImageComponent(BufferedImage bufferedImage)
	{
	    _bufferedImage = bufferedImage;
	}

	/**
	 * Paints the image into the specified Graphics.
	 *
	 * @param g Graphics to paint into.
	 */
	public void paint(Graphics g)
	{
	    Graphics2D g2d = (Graphics2D)g;
	    g2d.drawImage(_bufferedImage, 0, 0, null);
	}
    }

    /**
     * Reorders the registered Image Reader SPI's so that our SPI's take
     * preference over the default SPI's.
     */
    private static void _reorderImageReaderSpis()
    {
	IIORegistry registry = IIORegistry.getDefaultInstance();

	// Get all the registered Image Reader SPI's
	Iterator spis = registry.getServiceProviders(ImageReaderSpi.class,
						     true);

	// Clear the registry and load only SPI's from the classpath
	registry.deregisterAll(ImageReaderSpi.class);
	registry.registerApplicationClasspathSpis();

	// Lower the preference of the default SPI's
	String wbmpName = "com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi";
	while ( spis.hasNext() ) {
	    ImageReaderSpi spi = (ImageReaderSpi)spis.next();

	    // Do not add if already there or is WBMP (interfers with ANALYZE)
	    if ( !wbmpName.equals(spi.getClass().getName()) &&
		 !_isRegistered(spi) )
		{
		    registry.registerServiceProvider(spi, ImageReaderSpi.class);
		    _lowerPreference(spi);
		}
	}
    }

    /**
     * Determines if the specified Image Reader SPI is already registered.
     *
     * @param spi Image Reader SPI.
     *
     * @return True if the specified Image Reader SPI is already registered;
     *         false otherwise.
     */
    private static boolean _isRegistered(ImageReaderSpi spi)
    {
	IIORegistry registry = IIORegistry.getDefaultInstance();

	// Check all the currently registered SPI's
	Iterator spis = registry.getServiceProviders(ImageReaderSpi.class,
						     true);
	while ( spis.hasNext() ) {
	    ImageReaderSpi nextSpi = (ImageReaderSpi)spis.next();

	    // Check the classes
	    if ( spi.getClass() == nextSpi.getClass() ) { return true; }
	}

	// SPI is not registered
	return false;
    }

    /**
     * Lowers the preference of the the specified Image Reader SPI below the
     * other registered SPI's.  The specified SPI must be registered.
     *
     * @param lesserPreferenceSpi Image Reader SPI which is to be given a lower
     *                            preference.
     */
    private static void _lowerPreference(ImageReaderSpi lesserPreferenceSpi)
    {
	IIORegistry registry = IIORegistry.getDefaultInstance();

	// Get all the currently registered SPI's
	Iterator spis = registry.getServiceProviders(ImageReaderSpi.class,
						     true);
	while ( spis.hasNext() ) {
	    ImageReaderSpi spi = (ImageReaderSpi)spis.next();

	    // Lower the priority of the specified SPI w.r.t each registered SPI
	    if (spi != lesserPreferenceSpi) {
		registry.setOrdering(ImageReaderSpi.class, spi,
				     lesserPreferenceSpi);
	    }
	}
    }
}
